iT邦幫忙

2026 iThome 鐵人賽

DAY 13
0
Claude AI

從零開始 Claude Code:30 天打造 AI 任務管理 Web App系列 第 13 篇

[Day 13] 不再寫死任務:從 MySQL 顯示資料

  • 分享至 

  • xImage
  •  

Day 12 已經可以把新增任務真的存進 MySQL。
但首頁還有一個問題:

index.html

裡面的任務卡片仍然是以前手動寫死的假資料。
所以 Day 13 的目標是:
把首頁改成直接讀取 MySQL 裡真正的任務。
今天先只做「顯示資料」,不碰:

編輯
刪除
狀態修改
篩選
分類 CRUD
Claude API

先讓 Claude Code 規劃

我先告訴 Claude Code 目前的狀態:

目前狀態:

- Flask 已經成功連上 MySQL
- 已有 Category、Task Model
- /tasks/new 已經可以新增任務到 MySQL
- index.html 目前還是三筆寫死的假資料

今天只做:

1. 首頁從 MySQL 查詢所有 Task
2. 把 tasks 傳給 index.html
3. 使用 Jinja2 迴圈顯示任務
4. 顯示:
   - 任務名稱
   - 狀態
   - 分類
   - 截止日期
5. 移除原本三筆寫死的假資料
6. 沒有任務時顯示簡單提示

今天不要:

- 編輯
- 刪除
- 狀態修改
- 篩選
- 分類 CRUD
- services/
- routes/
- Claude API

請先規劃會修改哪些檔案,
不要直接修改程式。

最後確認只會修改:

app.py
models/task.py
templates/index.html

app.py:首頁開始查 MySQL

原本首頁只是:

@app.route("/")
def index():
    return render_template("index.html")

Day 13 改成:

@app.route("/")
def index():
    tasks = Task.query.order_by(
        Task.created_at.desc(),
        Task.id.desc(),
    ).all()

    return render_template("index.html", tasks=tasks)

這裡最重要的是:

Task.query

代表透過 Task Model 查詢 tasks 資料表。
而:

.all()

代表把所有任務查出來。


為什麼要排序?

這次使用:

Task.created_at.desc(),
Task.id.desc(),

代表:

建立時間新的先顯示
	   ↓
如果建立時間相同
       ↓
id 比較大的先顯示

這樣剛新增的任務會比較穩定地出現在首頁最上面。


Task Model 加入 Category 關聯

tasks 裡其實只存:

category_id

例如:

category_id = 3

但首頁想看到的是:

生活

所以在 models/task.py 加入:

category = db.relationship("Category")

這樣之後就可以直接:

task.category.name
task.category.color

不需要自己拿 category_id 再查一次。


把 status 轉成中文

MySQL 裡的狀態存的是:

todo
in_progress
done

但首頁要顯示:

待處理
進行中
已完成

所以 Task Model 加入:

STATUS_LABELS = {
    "todo": "待處理",
    "in_progress": "進行中",
    "done": "已完成",
}

以及:

@property
def status_label(self):
    return self.STATUS_LABELS.get(self.status, self.status)

這樣首頁就可以直接:

{{ task.status_label }}

CSS class 也一起處理

Day 8 已經有:

status-todo
status-progress
status-done

其中資料庫的 in_progress 對應到既有 CSS 的 status-progress,
兩邊名稱不完全相同,所以透過 STATUS_CSS_CLASSES 做轉換。

所以這次也加:

STATUS_CSS_CLASSES = {
    "todo": "status-todo",
    "in_progress": "status-progress",
    "done": "status-done",
}

以及:

@property
def status_css_class(self):
    return self.STATUS_CSS_CLASSES.get(self.status, "")

首頁就可以寫:

<span class="status-badge {{ task.status_css_class }}">
    {{ task.status_label }}
</span>

資料庫仍然存英文值,畫面才負責顯示中文和樣式。


index.html 改成 Jinja2 迴圈

Day 8 的首頁是三張手動寫死的:

<article class="task-card">
    ...
</article>

Day 13 改成:

{% for task in tasks %}

所以現在不是固定三張卡片,而是:

MySQL 有幾筆 Task
       ↓
首頁就顯示幾張卡片

任務名稱:

<h2>{{ task.title }}</h2>

狀態:

<span class="status-badge {{ task.status_css_class }}">
    {{ task.status_label }}
</span>

顯示分類

分類部分:

{% if task.category %}
    <span
        class="category-dot"
        style="background-color: {{ task.category.color }}">
    </span>
    {{ task.category.name }}
{% else %}
    未分類
{% endif %}

如果任務有分類,就顯示:

● 專案

如果 category_id 是 NULL,則顯示:

未分類

顯示截止日期

截止日期:

{% if task.due_date %}
    <time datetime="{{ task.due_date }}">
        {{ task.due_date.strftime('%Y/%m/%d') }}
    </time>
{% else %}
    未設定
{% endif %}

例如資料庫裡:

2026-10-01

首頁會顯示:

2026/10/01

如果沒有截止日期,就顯示:

未設定

完成的任務保留原本樣式

首頁原本就有:

task-completed

用來顯示已完成任務。
現在改成:

<article class="task-card{% if task.status == 'done' %} task-completed{% endif %}">

所以只有:

status = done

的任務才會套用完成樣式。


沒有任務時也要有提示

Jinja2 的 for 可以搭配 else:

{% for task in tasks %}
    ...
{% else %}
    <p class="empty-state">
        目前沒有任務,點右上角「新增任務」開始新增。
    </p>
{% endfor %}

如果 tasks 是空的,首頁不會整片空白,而是顯示提示。


實際測試

目前 MySQL 裡有兩筆資料。
首頁現在會直接顯示:

測試1
進行中
生活
2026/10/01

測試
待處理
專案
2026/09/26

https://ithelp.ithome.com.tw/upload/images/20260927/20183857LCmSFdcpzr.png
可以看到原本寫死的:

整理期末專題需求
完成首頁介面設計
建立 Flask 專案骨架

已經全部消失。


跟 Workbench 對照

再回到 MySQL Workbench:

SELECT * FROM tasks;

可以看到首頁顯示的兩筆資料確實存在 MySQL。
https://ithelp.ithome.com.tw/upload/images/20260927/20183857mbiHrFngEs.png
兩張圖對照後,可以確認:

MySQL
  ↓
Task Model
  ↓
Flask
  ↓
Jinja2
  ↓
首頁任務卡片

已經真的接起來。


新增任務也會立即出現在首頁

Day 12 已經可以新增任務。
所以現在再從:

/tasks/new

新增一筆資料後,回到首頁,就會直接看到新任務。
而且因為首頁有排序:

Task.created_at.desc(),
Task.id.desc(),

最新任務會顯示在前面。


今天做到這裡

Day 13 完成後,首頁終於不再依賴寫死的假資料。
目前已經可以做到:

新增任務
   ↓
存進 MySQL
   ↓
重新讀取
   ↓
首頁顯示

而且狀態、分類、截止日期也都能正常顯示。
目前還不能修改或刪除既有任務。
所以下一步就是開始補 CRUD 的 Update。


上一篇
[Day 12] 把任務真的存進 MySQL
下一篇
[Day 14] 任務寫錯怎麼辦?加入編輯功能
系列文
從零開始 Claude Code:30 天打造 AI 任務管理 Web App 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言